Pytest 使用总结

这里简单记录下自己目前掌握的pytest知识,后续用到更多再来补充。

pytest的安装

1
pip3 install -U pytest
1
pytest --version # 查看版本

pytest基本用法

单个测试

我们来看一个小例子

1
2
3
4
5
6
# func.py
def func(x):
return x+1

def test_answer():
assert func(3) == 5

func.py所在目录下启动pytest

1
pytest func.py

得到结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
joseph@MacBook-Pro  ~/work/lab/pytesttest  pytest func.py
============================= test session starts ==============================
platform darwin -- Python 3.6.5, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
rootdir: /Users/joseph/work/lab/pytesttest, inifile:
collected 1 item

func.py F [100%]

=================================== FAILURES ===================================
_________________________________ test_answer __________________________________

def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)

func.py:5: AssertionError
=========================== 1 failed in 0.06 seconds ===========================

由此可以看出

  • 单个测试时,可以在命令行直接以pytest 要测试的.py的方式来执行测试。文件名无需test_开头
  • 执行测试时,会自动执行文件中的test_开头的方法
  • 在测试方法中,可以直接使用assert,而无需像unittest一样记住许多类似于assertEquals()之类的方法。

多个测试

多个测试时可以直接在当前目录下执行命令

1
$ pytest

会自动寻找并执行当前目录及其包含的子目录下所有以test_为前缀或者以_test为后缀的文件。也就是遵循standard test discovery rules

Exceptionassert

1
2
3
4
5
6
7
import pytest
def f():
raise SystemExit(1)

def test_mytest():
with pytest.raises(SystemExit):
f()

test_mytest函数中,断言函数f会抛出SystemExit异常。

将多个test整合到一个类里

比如这样

class TestClass:

    def test_one(self):
        x = 'this'
        assert 'h' in x

    def test_two(self):
        x = 'hello'
        assert hasattr(x, 'check')

pytest进阶

fixtures

更多可参考

这里记录一种常见的用法。

我们在unittest中可以用setUp()tearDown()来实现测试环境的构造和析构。

比如一个测试数据库中取出的数据是否正确的类,setUp()中可以写连接数据库的代码,tearDown()中可以写释放数据库连接的代码。在执行每个测试方法时,setUp()tearDown()都会分别在开始和结尾处执行,这样在测试方法中就可以专注于测试逻辑,而无需在每一个测试函数中都写一次连接和释放代码。

那我们在pytest中怎么实现呢?

答案就是运用fixture

比如我们每个测试方法都需要一个SMTP类的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# test_func.py
import pytest

# 这里scope='function'代表每个测试方法都会执行一侧fixture
@pytest.fixture(scope='function')
def get_instance():
# 每个测试方法执行前都会执行包括yield在内之前的代码,相当于setUp()
smtp = smtplib.SMTP("smtp.gmail.com")
yield smtp # provide the fixture value
# 每次完成当前scope,即在本例中,
# 测试方法执行完毕后,会执行下面的代码
# 就相当于tearDown()
print("teardown smtp")
smtp.close()

def test_method_1(get_instance):
# 在这里传入的 get_instance 其实就是 get_instance函数的返回值
ins = get_instance

assert isinstance(ins, MyClass)
...

pytest常用参数

1
pytest -q test.py  # quiet reporting mode. 减少输出信息。

参考